「コンテキスト関数」のご紹介:Scala 3の新しい型表現(4)

Scala 3.3.4
最終更新:2020年7月11日

[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください

この記事では、コンテキスト関数について解説します。

コンテキスト関数

コンテキスト関数とは、コンテキスト引数のみをとる関数のことです。
コンテキスト関数の型は「コンテキスト関数型」です。

普通の関数は以下のように定義できますね。

type Executable[T] = ExecutionContext => T

コンテキスト関数は以下のように定義します。 ?=> 記号を使用するのがポイントです。

type Executable[T] = ExecutionContext ?=> T
given ec as ExecutionContext = ... def f(x: Int): ExecutionContext ?=> Int = ...

さきほど型エイリアスを定義したので、以下のように書くこともできます。

def f(x: Int): Executable[Int] = ...

このようにすると、引数が合成されます。
以下の書き方をするのと実質的に同じになります。

def f(x: Int)(using ExecutionContext): Int = ...

使用する場合には、引数を推論して補完してくれます。
これは便利ですね。

f(2)

あるいは、引数を明示的に渡すこともできます。
具体的には以下のように記述します。

f(2)(using ec)

コンテキスト関数リテラル

以下のような書き方は、コンテキスト関数リテラルと呼ばれます。

コンテキスト関数リテラルで書くと、コンテキスト関数を作ることができます。
この例の場合、xの型は(T_1, ..., T_n) ?=> Eとなります。

val x = (using x_1: T1, ..., x_n: Tn) => E

例えば、以下のようなメソッドがあるとします。

def g(arg: ExecutionContext ?=> Int) = ...

以下のように書くと

g(22)

このように展開されます。

g((using ev: ExecutionContext) => 22)

また、以下のように書くと、

g(f(2))

このように展開されます。

g((using ev: ExecutionContext) => f(2)(using ev))

また、以下のように書くと、

g(ExecutionContext ?=> f(3))

このように展開されます。

g((using ev: ExecutionContext) => f(3)(using ev))

これはそのままになります。

g((using ctx: ExecutionContext) => f(22)(using ctx))

サイト内検索